﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities;
using WFExtended.Framework.Scheduling;
using System.Drawing;
using System.ComponentModel;
using WFExtended.Activities.Designers;
using System.Activities.Validation;
using System.Linq.Expressions;
using System.Activities.Statements;
using System.Windows.Markup;
using Microsoft.CSharp.Activities;

/// \namespace WFExtended.Activities Core Activities Toolbox
namespace WFExtended.Activities
{
    /// <summary>
    /// Delays execution for a specified crontab expression
    /// <code>
    /// Crontab expression format:<br/>
    /// * * * * *<br/>
    /// - - - - -<br/>
    /// | | | | |<br/>
    /// | | | | +_____ day of week (0 - 6) (Sunday=0)<br/>
    /// | | | +_______ month (1 - 12)<br/>
    /// | | +_________ day of month (1 - 31)<br/>
    /// | +____________hour (0 - 23)<br/>
    /// +_____________ min (0 - 59)<br/><br/>
    /// Example of Cron Expression : <br/>
    /// 1) ==> "* 1-3 * * *"<br/>
    /// 2) ==> "* * * 1,3,5,7,9,11 *"<br/>
    /// 3) ==> "10,25,40 * * * *"<br/>
    /// 4) ==> "* * * 1,3,8 1-2,5"<br/><br/>
    /// </code>
    /// <code>
    /// <b>Xaml Example with a CSharpExpression : </b> <br /> <br/>
    /// <Activity
    ///   xmlns:wa="clr-namespace:WFExtended.Activities;assembly=WFExtended"> <br />
    /// &nbsp;  <wa:CronDelay>  <br />
    /// &nbsp; &nbsp;     <wa:CronDelay.CronExpression>  <br />
    /// &nbsp; &nbsp; &nbsp;       <InArgument x:TypeArguments="x:String">  <br />
    /// &nbsp; &nbsp; &nbsp;&nbsp;          <mca:CSharpValue x:TypeArguments="x:String">CronExpression</mca:CSharpValue>  <br />
    /// &nbsp; &nbsp; &nbsp;       </InArgument>  <br />
    /// &nbsp; &nbsp;     </wa:CronDelay.CronExpression>  <br />
    /// &nbsp;   </wa:CronDelay>  <br />
    /// </Activity><br/><br/>
    /// </code>
    /// <code>
    /// <b>Xaml Example with a Contant CronTab Expression : </b> <br /> <br/>
    /// <Activity
    ///  xmlns:wa="clr-namespace:WFExtended.Activities;assembly=WFExtended"><br />
    ///  &nbsp;<wa:CronDelay CronExpression="0-59 * * * *" /><br />
    ///  </Activity><br />
    /// </code>
    /// <see cref=""/>
    /// </summary>
    [Description("Delays execution for a specified crontab expression")]
    [ToolboxBitmapAttribute(typeof(EntryPoint), "Resources.CronDelayToolbox.bmp")]
    [Designer(typeof(CronDelayDesigner))]
    public sealed class CronDelay : NativeActivity
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public CronDelay()
        {
            _delayActivity.Duration = _delayDuration;
            CronExpression = new InArgument<string>();
        }

        private Variable<TimeSpan> _delayDuration = new Variable<TimeSpan>();

        private System.Activities.Statements.Delay _delayActivity = new System.Activities.Statements.Delay();

        /// <summary>
        /// Get or Set the CronExpression
        /// <remarks>
        /// Required Argument
        /// </remarks>
        /// </summary>
        [Browsable(true)]
        [RequiredArgument]
        [Description("Get or Set the CronEpression")]
        public InArgument<string> CronExpression { get; set; }

        /// <summary>
        /// Creates and validates a description of the activity’s arguments, variables, child activities, and activity delegates.
        /// </summary>
        /// <param name="metadata">The activity’s metadata that encapsulates the activity’s arguments, variables, child activities, and activity delegates.</param>
        protected override void CacheMetadata(NativeActivityMetadata metadata)
        {
            base.CacheMetadata(metadata);
            metadata.AddImplementationVariable(_delayDuration);
            metadata.AddImplementationChild(_delayActivity);
        }

        /// <summary>
        /// Runs the activity’s execution logic.
        /// </summary>
        /// <param name="context">The execution context in which the activity executes</param>
        protected override void Execute(NativeActivityContext context)
        {
            DateTime dateNow = DateTime.Now;           

            CrontabSchedule schedule = CrontabSchedule.Parse(CronExpression.Get(context));
            DateTime date2 = schedule.GetNextOccurrence(dateNow);
            TimeSpan delayTimeSpan = (TimeSpan)(date2 - dateNow);
            _delayDuration.Set(context, delayTimeSpan);
            

            context.ScheduleActivity(_delayActivity);
        }
    }
}
